/*
 * Copyright © 2024-2025 Wenze Wei
 *
 * This file is part of StadionOS.
 *
 * This Source Code Form is subject to the terms of the GNU General Public License, v. 2.0.
 * You can obtain a copy of the GPL at
 * https://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
 * the specific language governing rights and limitations under the License.
 */

#include "../include/malloc.h"

/**
 * @brief Allocates memory.
 *
 * This function allocates 'size' bytes of memory, returning a pointer to the allocated block.
 * The memory is allocated from a memory pool, and if a suitable block is not found, the function will expand the pool.
 *
 * @param size The size of the memory block to allocate.
 * @return void* A pointer to the allocated memory, or NULL on error.
 */
void *Smalloc(size_t size) {  
    if (size == 0) {
        return NULL;
    }

    size = ALIGN(size);
    pthread_mutex_lock(&mutex);

    TBlock *current = head;

    while (current) {
        if (current->free && current->size >= size) {
            current->free = 0;
            if (current->size > size + sizeof(TBlock)) {
                TBlock *new_block = (TBlock *)((char *)current + sizeof(TBlock) + size);
                new_block->size = current->size - size - sizeof(TBlock);
                new_block->next = current->next;
                new_block->free = 1;

                current->size = size;
                current->next = new_block;
            }
            pthread_mutex_unlock(&mutex);
            return (void *)(current + 1);
        }
        current = current->next;
    }

    pthread_mutex_unlock(&mutex);
    error = EENOMEM;
    return NULL;
}

/**
 * @brief Initializes the memory pool.
 *
 * This function initializes the memory pool with a block of 'total_size' bytes.
 *
 * @param total_size The size of the memory pool.
 */
void Sinit_memory_pool(size_t total_size) {
    head = (TBlock *)Smalloc(total_size);

    if (!head) {
        error = EENOMEM;
        return;
    }

    head->size = total_size - sizeof(TBlock);
    head->next = NULL;
    head->free = 1;
}

/**
 * @brief Cleans up the memory pool.
 *
 * This function frees the memory pool.
 */
void Scleanup_memory_pool() {  
    Sfree(head);
    head = NULL;
}
